Me encuentro con un problema simple que tiene una solución hacky de setTimeout(...,0) .
Mirando este código simple:
@Component({ selector: 'my-app', template: ` <div> <input value='Fill Data' type='button' (click)='fill()'/> <span *ngFor="let o of Items" class='mySpan'>Span To Detect<br></span> </div> `, }) export class App { Items:Array<number> = new Array<number>(); fill() { this.Items = [1,2,3,4,5,6,7,8,9,10] this.analyzeDom(); //this has to run here } analyzeDom() { alert($("div .mySpan").length) // "0" //BUT if I set this hacky trick , it works // setTimeout(function (){ alert($("div .mySpan").length)},0) // "10" } } Si hago clic en el botón, la alerta muestra "0". Entiendo por qué está sucediendo. Es porque Angular no completó su ciclo para completar el ngFor .
Sin embargo, hacer este truco con setTimeout(..,0) me parece un poco extraño y prefiero no confiar en él.
Pregunta:
¿Cuál es la forma correcta de "esperar la operación" en Angular? (para que vea "10") ?
1) Puede obligar a Angular a actualizar el DOM llamando a cdRef.detectChanges
constructor(private cdRef: ChangeDetectorRef) {} analyzeDom(){ this.cdRef.detectChanges(); alert($("div .mySpan").length) Como setTimeout es una macrotarea, por lo tanto, se está ejecutando el próximo ciclo de resumen. Significa que después de llamar a setTimeout , se verificará todo el árbol de componentes
cdRef.detectChanges no llama a appRef.tick() . Solo ejecuta el componente de detección de cambios en sí mismo y sus hijos.
2) o puede esperar hasta que Angulat haya actualizado DOM suscribiéndose a zone.onMicrotaskEmpty
import 'rxjs/add/operator/first'; constructor(private zone: NgZone) {} ... this.zone.onMicrotaskEmpty.first().subscribe(() => this.analyzeDom());Nota: el primer operador puede provocar una fuga de memoria. Ver https://github.com/angular/material2/issues/6905
Suscribirse a onMicrotaskEmpty no llama al ciclo de detección de cambios